//
//  BLEManager.m
//  KiWiPeniOSProject
//
//  Created by 曾威林 on 2017/8/27.
//  Copyright © 2017年 zjy. All rights reserved.
//

#import "BLEManager.h"
#import <UIKit/UIKit.h>

static BLEManager *shareObject;

#define SERVICE_UUID @"CCC1"//服务
#define CHARACTERISTIC_UUID_READ @"DDD0" //读
#define CHARACTERISTIC_UUID_SUBSCRIPT @"DDD1" //订阅
#define CHARACTERISTIC_UUID_WRITE @"DDD2" //写

#define BLUETOOTH_NAME @"iPhone"//蓝牙名称
#define TIMEOUT 10  //超时时间
#define Connected_Peripherals_UUID_Key @"Connected_Peripherals_UUID_Key"//用来保存已经连接过的蓝牙设备



@interface BLEManager()<CBCentralManagerDelegate,CBPeripheralDelegate>

@property (nonatomic, copy) BLESearchBlock bleSearcBlock;
@property (nonatomic, copy) BLEConnectBlock bleConnectBlock;
@property (nonatomic, copy) BLEReceiveDataBlock bleReceiveDataBlock;

@property (strong, nonatomic) CBCentralManager *centralManager;
@property (strong, nonatomic) CBPeripheral *connectedPeripheral;
@property (copy, nonatomic) NSString *connectedUUIDStr;

@property (strong, nonatomic) CBCharacteristic *subscriptCharacteristic;
@property (strong, nonatomic) CBCharacteristic *writeCharacteristic;
@property (strong, nonatomic) CBCharacteristic *readCharacteristic;

@property (strong, nonatomic)NSMutableArray<CBPeripheral *> *discoverPeripheralList;

@end

@implementation BLEManager

//创建一个单例
+ (instancetype)shareBLEManager {
    static dispatch_once_t onceToken;
    dispatch_once(&onceToken, ^{
        shareObject = [[BLEManager alloc] init];
    });
    return shareObject;
}


#pragma mark - 公有方法
//获取已经连接过的设备
- (void)getMatchedPeripheralsWithSearchBlock:(BLESearchBlock)bleSearchBlock {
    self.bleSearcBlock = bleSearchBlock;
    
    NSMutableArray<NSUUID *> * uuidMutableArray = [NSMutableArray array];
    
    NSUserDefaults *standaryUserDefault = [NSUserDefaults standardUserDefaults];
    NSArray<NSString *> *savedArray = [standaryUserDefault stringArrayForKey:Connected_Peripherals_UUID_Key];
    
    for (NSString *tempStr in savedArray) {
        [uuidMutableArray addObject:[[NSUUID UUID] initWithUUIDString:tempStr]];
    }
    
    NSArray<CBPeripheral *> * peripheralArray = [self.centralManager retrievePeripheralsWithIdentifiers:uuidMutableArray];
    if (peripheralArray.count > 1) {
        self.bleSearcBlock(YES, peripheralArray);
    } else {
        self.bleSearcBlock(NO, nil);
    }
}

//扫描设备
- (void)scanPeripheralsWithName:(NSString *) nameStr AndSearchBlock:(BLESearchBlock)bleSearchBlock {
    self.bleSearcBlock = bleSearchBlock;
    //限制只能搜索出指定UUid的设备
    CBUUID *serviceUUID = [CBUUID UUIDWithString:SERVICE_UUID];
    //调用系统方法
    [self.centralManager scanForPeripheralsWithServices:@[serviceUUID] options:nil];
}

//连接设备
- (void)connectWithPeripheral:(CBPeripheral *)peripheral AndConnectBlock:(BLEConnectBlock)bleConnectBlock AndReceiveBlock:(BLEReceiveDataBlock)bleReceiveDataBlock {
    self.bleConnectBlock = bleConnectBlock;
    self.bleReceiveDataBlock = bleReceiveDataBlock;
    //调用系统方法
    [self.centralManager connectPeripheral:peripheral options:nil];
}

//发送数据给蓝牙设备
- (void)writeDataWithData:(NSData *)data {
    //没有回复消息的类型
    [self.connectedPeripheral writeValue:data forCharacteristic:self.writeCharacteristic type:CBCharacteristicWriteWithoutResponse];
}

//主动从蓝牙设备读取数据
- (void)readData {
    [self.connectedPeripheral readValueForCharacteristic:self.readCharacteristic];
}

//取消扫描，断开连接
- (void)cancelAll {
    //防止重新连接
    self.connectedUUIDStr = nil;

    [self.centralManager cancelPeripheralConnection:self.connectedPeripheral];
    [self.centralManager stopScan];
    self.readCharacteristic = nil;
    self.writeCharacteristic = nil;
    self.subscriptCharacteristic = nil;
    self.connectedPeripheral = nil;
    self.centralManager = nil;
}

//缓存设备的UUID
- (void) saveConnectedPeripheralWithUUID:(NSString *) uuidStr {
    
    NSUserDefaults *standaryUserDefaults = [NSUserDefaults standardUserDefaults];
    NSMutableArray<NSString *> * savedArray = [NSMutableArray arrayWithArray:[standaryUserDefaults stringArrayForKey:Connected_Peripherals_UUID_Key]];
    for (NSString *tempStr in savedArray) {
        if ([tempStr isEqualToString:uuidStr]) {
            NSLog(@"已经存在，不需要再保存。");
            return;
        }
    }
    [savedArray addObject:uuidStr];
    [standaryUserDefaults setObject:savedArray forKey:Connected_Peripherals_UUID_Key];
    [standaryUserDefaults synchronize];
}

//删除缓存的设备UUID
- (void) deleteConnectedPeripheralWithUUID:(NSString *) uuidStr {
    
    NSUserDefaults *standaryUserDefaults = [NSUserDefaults standardUserDefaults];
    NSMutableArray<NSString *> * savedArray = [NSMutableArray arrayWithArray:[standaryUserDefaults stringArrayForKey:Connected_Peripherals_UUID_Key]];
    [savedArray enumerateObjectsUsingBlock:^(NSString * _Nonnull obj, NSUInteger idx, BOOL * _Nonnull stop) {
        if ([obj isEqualToString:uuidStr]) {
            [savedArray removeObject:obj];
        }
    }];
    
    [standaryUserDefaults setObject:savedArray forKey:Connected_Peripherals_UUID_Key];
    [standaryUserDefaults synchronize];
}

#pragma mark - 懒加载
//懒加载,创建centralmanager
- (CBCentralManager *)centralManager {
    if (!self.centralManager) {
        NSDictionary<NSString *, id> *options = @{CBCentralManagerOptionShowPowerAlertKey: @(NO)};
        self.centralManager = [[CBCentralManager alloc]initWithDelegate:self queue:dispatch_get_main_queue() options:options];
    }
    return self.centralManager;
}

//懒加载，初始化discoverperipherallist
- (NSMutableArray<CBPeripheral *> *)discoverPeripheralList {
    if (!self.discoverPeripheralList) {
        self.discoverPeripheralList = [NSMutableArray array];
    }
    return self.discoverPeripheralList;
}

#pragma mark - 以下都是cbcentralmanager代理方法

//中心设备状态更新后调用CBCentralManagerStatePoweredOff,CBCentralManagerStatePoweredOn
- (void)centralManagerDidUpdateState:(CBCentralManager *)central {
    if (central.state == CBCentralManagerStatePoweredOff) {
        NSLog(@"蓝牙已经关闭");
        //请求蓝牙权限
        [self requestUserBlueToothAuth];

    }else if(central.state == CBCentralManagerStatePoweredOn) {
        NSLog(@"蓝牙已经打开");
    }
}

//进入后台前调用
- (void)centralManager:(CBCentralManager *)central willRestoreState:(NSDictionary<NSString *, id> *)dict {
    
}

//发现外设时调用
- (void)centralManager:(CBCentralManager *)central didDiscoverPeripheral:(CBPeripheral *)peripheral advertisementData:(NSDictionary<NSString *, id> *)advertisementData RSSI:(NSNumber *)RSSI {
    
    //过滤掉已经配对过的设备
    NSUserDefaults *standaryUserDefault = [NSUserDefaults standardUserDefaults];
    NSArray<NSString *> *savedArray = [standaryUserDefault stringArrayForKey:Connected_Peripherals_UUID_Key];
    
    for (NSString *tempStr in savedArray) {
        if ([tempStr isEqualToString:peripheral.identifier.UUIDString]) {
            return;
        }
    }
    
    
    //为了不重复添加到数组中的判断
    for (int i = 0; i < self.discoverPeripheralList.count; i++) {

        if (self.discoverPeripheralList[i].identifier.UUIDString == peripheral.identifier.UUIDString) {
           //uuid是识别的唯一标志，同一设备可创建多个对象,做内容替换
            self.discoverPeripheralList[i] = peripheral;
        }else {
            [self.discoverPeripheralList addObject:peripheral];
        }
    }
    self.bleSearcBlock(YES, self.discoverPeripheralList);
}

//连接上外设时调用
- (void)centralManager:(CBCentralManager *)central didConnectPeripheral:(CBPeripheral *)peripheral {
    //要先连接服务，然后连接到characteristic才算连接成功，先保存peripheral
    //发现的时候就可以给peripheral对象赋值代理了
    peripheral.delegate = self;
    self.connectedPeripheral = peripheral;
    self.connectedUUIDStr = peripheral.identifier.UUIDString;
    
    //限制只能搜索出指定UUid的设备
    CBUUID *serviceUUID = [CBUUID UUIDWithString:SERVICE_UUID];
    //连接服务
    [peripheral discoverServices:@[serviceUUID]];
}

//连接外设失败时调用
- (void)centralManager:(CBCentralManager *)central didFailToConnectPeripheral:(CBPeripheral *)peripheral error:(nullable NSError *)error {
    NSLog(@"连接外设失败%@",error);
    self.bleConnectBlock(NO);
}

//掉线和主动断开时调用
- (void)centralManager:(CBCentralManager *)central didDisconnectPeripheral:(CBPeripheral *)peripheral error:(nullable NSError *)error {
    NSLog(@"连接上以后，设备掉线或主动断开了");
    self.bleConnectBlock(NO);
    //重连
    if (self.connectedUUIDStr.length > 0) {//需要重新连接
        NSUUID *uuid = [[NSUUID UUID] initWithUUIDString:self.connectedUUIDStr];
        NSArray *tempArray = [central retrievePeripheralsWithIdentifiers:@[uuid]];
        if (tempArray.count > 0) {
            self.connectedPeripheral = tempArray[0];
            self.connectedPeripheral.delegate = self;
            [central connectPeripheral:self.connectedPeripheral options:nil];
            NSLog(@"尝试重新连接。");
        }
    }
}

#pragma mark - 以下是peripheral代理方法
//peripheral更新名字
- (void)peripheralDidUpdateName:(CBPeripheral *)peripheral {
    
}

//peripheral编辑服务
- (void)peripheral:(CBPeripheral *)peripheral didModifyServices:(NSArray<CBService *> *)invalidatedServices {
    
}

//peripheral更新rssi
- (void)peripheralDidUpdateRSSI:(CBPeripheral *)peripheral error:(nullable NSError *)error {
    
}

//peripheral读取到rssi
- (void)peripheral:(CBPeripheral *)peripheral didReadRSSI:(NSNumber *)RSSI error:(nullable NSError *)error {
    
}

//peripheral发现服务
- (void)peripheral:(CBPeripheral *)peripheral didDiscoverServices:(nullable NSError *)error {
    if (error) {
        NSLog(@"discover  Service失败%@",error);
    }else {
        //获取characteristic
        CBUUID *readUUID = [CBUUID UUIDWithString:CHARACTERISTIC_UUID_READ];
        CBUUID *subscriptUUID = [CBUUID UUIDWithString:CHARACTERISTIC_UUID_SUBSCRIPT];
        CBUUID *writeUUID = [CBUUID UUIDWithString:CHARACTERISTIC_UUID_WRITE];
        
        for (int i = 0; i < peripheral.services.count; i++) {
            if ([peripheral.services[i].UUID.UUIDString isEqualToString:SERVICE_UUID]) {
                [peripheral discoverCharacteristics:@[readUUID,subscriptUUID,writeUUID] forService:peripheral.services[i]];
            }
        }
    }
}

//peripheral发现指定服务的包含服务
- (void)peripheral:(CBPeripheral *)peripheral didDiscoverIncludedServicesForService:(CBService *)service error:(nullable NSError *)error {
    
}

//peripheral发现指定服务的characteristics
- (void)peripheral:(CBPeripheral *)peripheral didDiscoverCharacteristicsForService:(CBService *)service error:(nullable NSError *)error {
    if (error) {
        NSLog(@"发现指定服务的characteristic失败%@",error);
        self.bleConnectBlock(NO);
    }else {
        NSLog(@"发现指定服务的characteristic成功");
        self.bleConnectBlock(YES);
        
        for (int i = 0; i < service.characteristics.count; i++) {
            if ([service.characteristics[i].UUID.UUIDString isEqualToString:CHARACTERISTIC_UUID_WRITE]) {
                NSLog(@"读");
                self.writeCharacteristic = service.characteristics[i];
                //[peripheral readValueForCharacteristic:service.characteristics[i]];
            }else if ([service.characteristics[i].UUID.UUIDString isEqualToString:CHARACTERISTIC_UUID_SUBSCRIPT]) {
                NSLog(@"订阅");
                self.subscriptCharacteristic = service.characteristics[i];
                //订阅
                [peripheral setNotifyValue:YES forCharacteristic:self.subscriptCharacteristic];
            }else if ([service.characteristics[i].UUID.UUIDString isEqualToString:CHARACTERISTIC_UUID_READ]) {
                NSLog(@"写");
                self.writeCharacteristic = service.characteristics[i];
            }
        }
    }
}

//peripheral更新指定characteristic的值
- (void)peripheral:(CBPeripheral *)peripheral didUpdateValueForCharacteristic:(CBCharacteristic *)characteristic error:(nullable NSError *)error {
    //读取数据成功
    if (error) {
        NSLog(@"读取数据失败%@",error);
    }else {
        NSLog(@"读取数据成功");
        if ([characteristic.UUID.UUIDString isEqualToString:CHARACTERISTIC_UUID_READ]) {
            NSLog(@"read收到数据");
            self.bleReceiveDataBlock(characteristic.value);
        }else if ([characteristic.UUID.UUIDString isEqualToString:CHARACTERISTIC_UUID_SUBSCRIPT]) {
            NSLog(@"subscript收到数据");
            self.bleReceiveDataBlock(characteristic.value);
        }
    }
}

//写入指定characteristic的值
- (void)peripheral:(CBPeripheral *)peripheral didWriteValueForCharacteristic:(CBCharacteristic *)characteristic error:(nullable NSError *)error {
    if (error) {
        NSLog(@"写入数据失败%@",error);
    }else{
       NSLog(@"写入数据成功");
        
        
    }
}

//更新指定characteristic的notification
- (void)peripheral:(CBPeripheral *)peripheral didUpdateNotificationStateForCharacteristic:(CBCharacteristic *)characteristic error:(nullable NSError *)error {
    if (error) {
        NSLog(@"更新notification失败%@",error);
    }else {
        if (characteristic.isNotifying) {
            NSLog(@"订阅成功，uuid:%@", characteristic.UUID.UUIDString);
        } else {
            NSLog(@"取消订阅，uuid:%@", characteristic.UUID.UUIDString);
        }
    }
}

//发现指定characteristic的描述
- (void)peripheral:(CBPeripheral *)peripheral didDiscoverDescriptorsForCharacteristic:(CBCharacteristic *)characteristic error:(nullable NSError *)error {
    
}

//更新指定descriptor的值
- (void)peripheral:(CBPeripheral *)peripheral didUpdateValueForDescriptor:(CBDescriptor *)descriptor error:(nullable NSError *)error {
    
}

//写入指定Descriptor的值
- (void)peripheral:(CBPeripheral *)peripheral didWriteValueForDescriptor:(CBDescriptor *)descriptor error:(nullable NSError *)error {
    
}

#pragma mark - 权限申请
//向用户请求蓝牙权限
- (void) requestUserBlueToothAuth {
    UIAlertController *alert = [UIAlertController alertControllerWithTitle:@"打开蓝牙提醒" message:@"使用奇异笔设备需要您打开蓝牙" preferredStyle:UIAlertControllerStyleAlert];
    [alert addAction:[UIAlertAction actionWithTitle:@"设置" style:UIAlertActionStyleDefault handler:^(UIAlertAction * _Nonnull action) {
        
        [self openBlueToothSetting];
        
    }]];
    
    //如果用户没有打开蓝牙， 提示用户打开，并且做相应动作
    UIViewController *appRootVC = [UIApplication sharedApplication].keyWindow.rootViewController;
    UIViewController *topVC = appRootVC;
    while (topVC.presentedViewController) {
        topVC = topVC.presentedViewController;
    }
    
    [topVC presentViewController:alert animated:YES completion:^{
    }];
}

//打开蓝牙设置
- (void) openBlueToothSetting {
    
    NSString * urlString = @"App-Prefs:root=Bluetooth";
    if ([[UIApplication sharedApplication] canOpenURL:[NSURL URLWithString:urlString]]) {
        
        if ([UIDevice currentDevice].systemVersion.floatValue > 10.0) {
            
            [[UIApplication sharedApplication] openURL:[NSURL URLWithString:urlString] options:@{} completionHandler:^(BOOL success) {
                
            }];
            
        } else {
            
            [[UIApplication sharedApplication] openURL:[NSURL URLWithString:urlString]];
            
        }
    }
}

@end
